#include "ZipWrapper.h"

#include "zlib.h"
#include "unzip.h"
#include "zip.h"

#include <QDir>

#include <QDebug>

#define MAX_PATH 260

using namespace std;

ZipWrapper::ZipWrapper()
{

}

std::string ZipWrapper::UnzipFile(const std::string& strFilePath, const std::string &dstPath)
{
    std::string loadPath;

    QDir dir(dstPath.c_str());
    if (!dir.mkpath(dstPath.c_str())) {
        emit unzipStatus(false,"dir error");
        return "";
    }

    int nReturnValue;
    string tempFilePath;
    string srcFilePath(strFilePath);
    string destFilePath;

    qDebug() << "Start unpacking the package... ";

    // 打开zip文件
    unzFile unzfile = unzOpen(srcFilePath.c_str());
    if (unzfile == NULL)
    {
        emit unzipStatus(false,"open error");
        return loadPath;
    }

    // 获取zip文件的信息
    unz_global_info* pGlobalInfo = new unz_global_info;
    nReturnValue = unzGetGlobalInfo(unzfile, pGlobalInfo);
    if (nReturnValue != UNZ_OK)
    {
        qDebug() << "The number of compressed package files is  " << pGlobalInfo->number_entry;
        emit unzipStatus(false,"zip init error");
        return loadPath;
    }


    // 解析zip文件
    unz_file_info* pFileInfo = new unz_file_info;
    char szZipFName[MAX_PATH] = { 0 };
    char szExtraName[MAX_PATH] = { 0 };
    char szCommName[MAX_PATH] = { 0 };
    // 存放从zip中解析出来的内部文件名
    for (int i = 0; i < pGlobalInfo->number_entry; i++)
    {
        // 解析得到zip中的文件信息
        nReturnValue = unzGetCurrentFileInfo(unzfile, pFileInfo, szZipFName, MAX_PATH, szExtraName, MAX_PATH, szCommName, MAX_PATH);
        if (nReturnValue != UNZ_OK) {
            emit unzipStatus(false,"parse error");
            return loadPath;
        }

        if (i == 0) {
            loadPath = szZipFName;
        }
        //        qDebug() << "ZipName: " << szZipFName << "Extra: " << szExtraName << "Comm: " << szCommName;

        string strZipFName = szZipFName;
        if ((strZipFName.rfind('/') == strZipFName.length() - 1))
        {
            destFilePath = dstPath + "//" + szZipFName;
            QDir dir(destFilePath.c_str());
            dir.mkpath(destFilePath.c_str());
        } else
        {
            // 创建文件
            string strFullFilePath;
            tempFilePath = dstPath + "/" + szZipFName;
            strFullFilePath = tempFilePath;// 保存完整路径

            int nPos = tempFilePath.rfind("/");
            int nPosRev = tempFilePath.rfind("\\");
            if (nPosRev == string::npos && nPos == string::npos)
                continue;

            size_t nSplitPos = nPos > nPosRev ? nPos : nPosRev;
            destFilePath = tempFilePath.substr(0, nSplitPos + 1);

            if (!QDir(destFilePath.c_str()).exists())
            {
                QDir dir(destFilePath.c_str());
                dir.mkpath(destFilePath.c_str());
            }

            QFile hFile(strFullFilePath.c_str());
            if (!hFile.open(QIODevice::WriteOnly)) {
                emit unzipStatus(false,"file open error");
                return loadPath;
            }

            // 打开文件
            nReturnValue = unzOpenCurrentFile(unzfile);
            if (nReturnValue != UNZ_OK)
            {
                hFile.close();
                emit unzipStatus(false,"open file error");
                return loadPath;
            }

            // 读取文件
            uLong BUFFER_SIZE = pFileInfo->uncompressed_size;;
            void* szReadBuffer = NULL;
            szReadBuffer = (char*)malloc(BUFFER_SIZE);
            if (NULL == szReadBuffer)
            {
                break;
            }

            while (true)
            {
                memset(szReadBuffer, 0, BUFFER_SIZE);
                int nReadFileSize = 0;

                nReadFileSize = unzReadCurrentFile(unzfile, szReadBuffer, BUFFER_SIZE);

                if (nReadFileSize < 0)					 // 读取文件失败
                {
                    unzCloseCurrentFile(unzfile);
                    hFile.close();
                    emit unzipStatus(false,"read file error");
                    return loadPath;
                }
                else if (nReadFileSize == 0)           // 读取文件完毕
                {
                    unzCloseCurrentFile(unzfile);
                    hFile.close();
                    break;
                }
                else									// 写入读取的内容
                {
                    bool bWriteSuccessed = hFile.write((const char*)szReadBuffer,BUFFER_SIZE);
                    if (!bWriteSuccessed)
                    {
                        unzCloseCurrentFile(unzfile);
                        hFile.close();
                        emit unzipStatus(false,"write file error");
                        return loadPath;
                    }
                }
            }

            free(szReadBuffer);
        }
        unzGoToNextFile(unzfile);
    }

    delete pFileInfo;

    delete pGlobalInfo;

    // 关闭
    if (unzfile)
    {
        unzClose(unzfile);
    }
    qDebug() << "End unpacking the package... ";

    emit unzipStatus(true,"");

    return loadPath;
}
